/*******************************************************************************
 * Copyright 2007, 2009 InnovaSoft SA http://www.innovasoft.biz/
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************/
 
package biz.innovasoft.ndb;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

import biz.innovasoft.ndb.annotations.Query;
import biz.innovasoft.ndb.annotations.Transaction;
import biz.innovasoft.ndb.annotations.TransactionWithQuery;
import biz.innovasoft.ndb.index.DateResolution;
import biz.innovasoft.ndb.query.QueryCriteria;
import biz.innovasoft.ndb.query.QueryType;
import biz.innovasoft.ndb.query.Tuple;

/**
 * 
 * This is the access point to the objects in the repository. This interface allows to store,
 * update, delete objects, create indexes, and find objects in the repository.
 * 
 * A repository is created using the PrevalentRepositoryManager. To open a repository is very 
 * simple, as we can see below:
 *  
 * Repository repository = PrevalentRepositoryManager.getInstance().openRepository("MyRepo");
 * 
 *  
 * @author Diego Miranda
 * @see RepositoryConfiguration
 */

public interface Repository extends Serializable {

	/**
	 * Returns the number of objects in the repository.
	 * 
	 * @return	the number of objects in the repository.
	 */
	public int size();
	
	/**
	 * Returns the number of objects with the class type.
	 * 
	 * @param clazz the type of objects to look for.
	 * @return the number of objects with the class type.
	 */
	public int size(Class<?> clazz);

	/**
	 * Returns the object by the oid.
	 * 
	 * @param oid  the objects id
	 * @return the object in the repository.
	 * @throws ObjectNotFoundException in case that the oid is inexistant.
	 */
	@Query public Object getByOId(Integer oid);
	
	/**
	 * Returns the object by the oid.
	 * 
	 * @param oid  the objects id
	 * @return the object in the repository.
	 * @throws ObjectNotFoundException in case that the oid is inexistant.
	 */
	@Query public Object getByOId(Long oid);

	/**
	 * Returns all the objects in the repository.
	 * 
	 * @return a list of tuples with all the objects in the repository.
	 * 
	 */
	@Query public List<Tuple> getAll();

	/**
	 * Returns all the objects of the specified class in the repository
	 * 
	 * @param clazz the class to be found.
	 * @return a list of tuples with all the objects of the specified class.
	 */
	@Query public List<Tuple> getAll(Class<?> clazz);
	
	/**
	 * Returns all the objects of the specified class in the repository
	 * 
	 * @param clazz the class to be found.
	 * @return a list of tuples with all the objects of the specified class.
	 */
	@Query public List<Tuple> getAll(Class<?> clazz, int first);
	
	/**
	 * Find all the objects of the specified class in the repository, and then 
	 * execute the filter over the selected objects.
	 * 
	 * @param clazz	the class to be found.
	 * @param filter the filter to be applied over the object of the specified class.
	 * @return a list of tuples with all the objects that matched the filter.
	 */
	@Query public List<Tuple> getAllWithFilter (Class<?> clazz, Filter filter);

	/**
	 * Returns all the objects Ids.
	 * 
	 * @return returns all the objects ids.
	 */
	@Query public Long[] getOIds();

	/**
	 * Returns a list of tuples containing all the objects with the specified oids.
	 *  
	 * @param ids a collection of objects ids.
	 * @return a list of tuples containing all the objects with the specified oids.
	 * @throws ObjectNotFoundException if one of the ids specified in the collection 
	 * does not exists.
	 */
	@Query public List<Tuple> getObjectsByOId(Collection<Long> ids);

	/**
	 * Returns a list of tuples containing all the objects with the oids specified by 
	 * parameter.
	 * 
	 * @param ids oids to retrieve.
	 * @return a list of tuples
	 */
	@Query public List<Tuple> getObjectsByOId(Long[] ids);
	
	/**
	 * Stores an object in the repository and index the object.
	 * 
	 * @param object the object to be stored in the repository.
	 * @return the OID that identify the object inserted in the repository.
	 * @throws RepositoryException
	 */
	@TransactionWithQuery public Long store(Object object) throws RepositoryException;

	/**
	 * Stores an object in the repository.
	 * 
	 * @param object the object to be stored in the repository.
	 * @param index true if you want the object to be indexed, false if you do not want to index
	 * the object.
	 * @return the OID that identify the object inserted in the repository. 
	 * @throws RepositoryException
	 */
	@TransactionWithQuery Long store(Object object, boolean index)
			throws RepositoryException;

	/**
	 * Stores an object in the repository.
	 * 
	 * @param objects the collection of objects to be stored in the repository.
	 * @param index true if you want the object to be indexed, false if you do not want to index
	 * the object.
	 * @return the OID that identify the object inserted in the repository. 
	 * @throws RepositoryException
	 */
	@TransactionWithQuery public Long[] store(Collection<?> objects, boolean index)
			throws RepositoryException;

	/**
	 * Updates the object in the repository and index it.
	 * 
	 * @param oid the oid that identify this object inside the repository.
	 * @param object the object to be updated.
	 * @return the previous object.
	 * @throws RepositoryException
	 */
	@TransactionWithQuery public Object update(Long oid, Object object) throws RepositoryException;
	
	/**
	 * Updates objects in the repository.
	 * 
	 * @param tuples a List of tuples containing the objects to modify.
	 * @throws RepositoryException
	 */
	@Transaction public void update(List<Tuple> tuples) throws RepositoryException;

	/**
	 * Updates the object in the repository.
	 * 
	 * @param oid the oid that identify this object inside the repository.
	 * @param object the object to be updated.
	 * @param index false if you want the object must not get indexed.
	 * @return the previous object.
	 * @throws RepositoryException
	 */
	@TransactionWithQuery
	public Object update(Long oid, Object object, boolean index)
			throws RepositoryException;
	
	/**
	 * Reindex all the objects in the repository. If you store or update objects with the index
	 * parameter in false, you should execute this method in order to get those objects updated
	 *  in the indexes.
	 *  
	 * @throws RepositoryException
	 */
	@Transaction public void reindex() throws RepositoryException;

	/**
	 * Reindex all objects of the specified class.
	 * 
	 * @param clazz the class that specifies what objects must be indexed.
	 * @throws RepositoryException
	 */
	@Transaction public void reindex(Class<?> clazz) throws RepositoryException;

	/**
	 * Creates an index for the specified class inside the repository.
	 * 
	 * @param clazz the class being indexed.
	 * @param indexPath the path in the object graph being indexed.
	 */
	@Transaction public void createIndex(Class<?> clazz, String indexPath);

	/**
	 * Creates an index for the specified class inside the repository.
	 * 
	 * @param clazz the class being indexed.
	 * @param indexPath the path in the object graph being indexed.
	 * @param allowNulls true if the index will allow nulls as a value.
	 */
	@Transaction public void createIndex(Class<?> clazz, String indexPath, boolean allowNulls);
	
	/**
	 * Creates an index for the specified class inside the repository. This method is used when
	 * you want to index a Date field, and change the resolution.
	 * 
	 * @param clazz the class being indexed.
	 * @param indexPath the path in the object graph being indexed.
	 * @param resolution the time granularity. YEAR, MONTH, DAY, HOUR, MINUTE, SECOND or MILLISECOND.
	 * @param allowNulls true if the index will allow nulls as a value.
	 */
	@Transaction public void createIndex(Class<?> clazz, String indexPath, DateResolution resolution, boolean allowNulls);

	/**
	 * Deletes an object by the oid.
	 * 
	 * @param oid the oid that identifies an object inside the repository.
	 * @return the object deleted.
	 * @throws RepositoryException
	 */
	@TransactionWithQuery public Object delete(Integer oid) throws RepositoryException;
	
	/**
	 * Deletes an object by the oid.
	 * 
	 * @param oid the oid that identifies an object inside the repository.
	 * @return the object deleted.
	 * @throws RepositoryException
	 */
	@TransactionWithQuery public Object delete(Long oid) throws RepositoryException;

	/**
	 * Deletes an object by the oid.
	 * 
	 * @param oid the oids that identifies the object to be deleted.
	 * @return the object deleted.
	 * @throws RepositoryException
	 */
	@Transaction public void delete(Long[] oid) throws RepositoryException;
	
	/**
	 * Deletes all the objects of the specified class.
	 * 
	 * @param clazz the class type to delete the objects.
	 * @throws RepositoryException
	 */
	@Transaction public void delete (Class<?> clazz) throws RepositoryException;
	/**
	 * Executes a deterministic action inside the repository. If you need to update an object
	 * and the update depends in some validations, you must execute this code into a deterministic
	 * action.
	 * 
	 * @param action a deterministic action that runs inside the repository.
	 * @param args the arguments passed to the action.
	 * @return if needed, the action could return any value.
	 * @throws Exception if needed, the action could throws an execption to inform prevayler 
	 * that the action is invalid.
	 */
	@TransactionWithQuery public Object executeDeterministic(Deterministic action, Object... args)
			throws Exception;

	/**
	 * Instruct Prevayler to take a snapshot of the repository.
	 */
	public void takeSnapshot();

	/**
	 * 
	 * Creates the criteria to query the repository.
	 * 
	 */
	public QueryCriteria createCriteria (Class<?> clazz);

	/**
	 * 
	 * Creates the criteria to query the repository.
	 * 
	 */
	public QueryCriteria createCriteria (Class<?> clazz, QueryType type);
	
	/**
	 * 
	 * Creates the criteria to query the repository.
	 * 
	 */
	public QueryCriteria createCriteria (Class<?> clazz, boolean stricted);
	
	/**
	 * 
	 * Creates the criteria to query the repository.
	 * 
	 */
	public QueryCriteria createCriteria (Class<?> clazz, boolean stricted, QueryType type);
}

